`define DELAY(N, clk) begin \
	repeat(N) @(posedge clk);\
	#1ps;\
end

module testbench();

//-------------------------------------{{{common cfg
timeunit 1ns;
timeprecision 1ps;
initial $timeformat(-9,3,"ns",6);

string tc_name;
int tc_seed;

initial begin
    if(!$value$plusargs("tc_name=%s", tc_name)) $error("no tc_name!");
    else $display("tc name = %0s", tc_name);
    if(!$value$plusargs("ntb_random_seed=%0d", tc_seed)) $error("no tc_seed");
    else $display("tc seed = %0d", tc_seed);
end
//-------------------------------------}}}

//-------------------------------------{{{parameter declare
parameter NOP   = 4'b0000;
parameter ADD   = 4'b0001;
parameter SUB   = 4'b0010;
parameter AND   = 4'b0011;
parameter NOT   = 4'b0100;

parameter LOAD  = 4'b0101;
parameter STORE = 4'b0110;
parameter BR    = 4'b0111;
parameter BRZ   = 4'b1000;

parameter HALT  = 4'b1111;

parameter CR0_ID  = 2'd0;
parameter CR1_ID  = 2'd1;
parameter CR2_ID  = 2'd2;
parameter CR3_ID  = 2'd3;
//-------------------------------------}}}

//-------------------------------------{{{signal declare
logic  clk;
logic  rst_n;
//-------------------------------------}}}

//-------------------------------------{{{clk/rst cfg
initial forever #5ns clk = ~clk;
initial begin
    rst_n = 1'b0;
	`DELAY(30, clk);
	rst_n = 1'b1;
end
initial begin
    #100000ns $finish;
end
//-------------------------------------}}}

//-------------------------------------{{{valid sig assign
//-------------------------------------}}}

//-------------------------------------{{{ready sig assign
//-------------------------------------}}}

//-------------------------------------{{{data  sig assign
//-------------------------------------}}}

//-------------------------------------{{{other sig assign
initial begin
    `DELAY(50, clk);
end

//-------------------------------------}}}

//-------------------------------------{{{rtl inst
tyrc_core u_tyrc_core(
    .clk(clk),
    .rst_n(rst_n)
);
//-------------------------------------}}}
task init_mem();
    for(int i=0; i<=8'hff; i+=1) begin
        u_tyrc_core.u_mem.mem[i] = '0;
    end
endtask

task gen_inst_q();
    //{INST , SRC, DST}

    //read 'hff to R1
    u_tyrc_core.u_mem.mem[0] = {LOAD, CR0_ID, CR1_ID};
    u_tyrc_core.u_mem.mem[1] = 8'hff;

    //read 'hfe to R0
    u_tyrc_core.u_mem.mem[2] = {LOAD, CR0_ID, CR0_ID};
    u_tyrc_core.u_mem.mem[3] = 8'hfe;

    //r1 = r0 + r1
    u_tyrc_core.u_mem.mem[4] = {ADD, CR0_ID, CR1_ID};

    //r2 = ~r1
    u_tyrc_core.u_mem.mem[5] = {NOT, CR1_ID, CR2_ID};

    //write r2 to 'hfd
    u_tyrc_core.u_mem.mem[6] = {STORE, CR2_ID, CR2_ID};
    u_tyrc_core.u_mem.mem[7] = 8'hfd;

    //read 'hfd to r3
    u_tyrc_core.u_mem.mem[8] = {LOAD, CR0_ID, CR3_ID};
    u_tyrc_core.u_mem.mem[9] = 8'hfd;

    //br
    u_tyrc_core.u_mem.mem[10] = {BR, CR0_ID, CR3_ID};
    u_tyrc_core.u_mem.mem[11] = 8'hfc;

    //sub
    u_tyrc_core.u_mem.mem[20] = {SUB, CR3_ID, CR3_ID};
        
    //brz
    u_tyrc_core.u_mem.mem[21] = {BRZ, CR0_ID, CR3_ID};
    u_tyrc_core.u_mem.mem[22] = 8'hfb;

    //nop
    u_tyrc_core.u_mem.mem[30] = {NOP, CR3_ID, CR3_ID};
    
    //halt
    u_tyrc_core.u_mem.mem[31] = {HALT, CR3_ID, CR3_ID};

endtask

task gen_data_q();
    u_tyrc_core.u_mem.mem[8'hff] = 8'hff;
    u_tyrc_core.u_mem.mem[8'hfe] = 8'hfe;
    u_tyrc_core.u_mem.mem[8'hfc] = 20;
    u_tyrc_core.u_mem.mem[8'hfb] = 30;
endtask

initial begin
    init_mem();
    gen_inst_q();
    gen_data_q();
end

endmodule
